<?php
/**
 * Author：晴天 QQ：1186258278
 * Creation：2020/5/21 14:58
 * Filename：AppOperation.php
 * 应用商店操作类
 */

namespace lib\AppStore;


use Curl\Curl;
use lib\Hook\Hook;
use Medoo\DB\SQL;

class AppList
{
    /**
     * @param $Input 字段名称
     * 下单信息接口匹配！
     * 1、验证是否有验证规则
     * 2、验证是否包含
     * 3、验证是否有同名字段
     * 4、如果有，输出对应内容！
     */
    public static function MatchingInput($Input)
    {
        $Rule = $_SESSION['Rule'];
        if (count($Rule) == 0) return false;

        foreach ($Rule as $key => $value) {
            if (!strstr($key, $Input)) continue;
            if (in_array($Input, explode('|', $key))) {
                if ($value['type'] == -1 && strstr($value['url'], '[url]')) {
                    $value['url'] = str_replace("[url]", is_https(false) . href(), $value['url']);
                }
                return $value;
            }
        }
        return false;
    }

    /**
     * @param int $type 1读取详细，2读取大概
     * @return array|bool
     * 读取悬停应用列表！
     * 未安装应用会过滤
     */
    public static function HoverList($type = 1)
    {
        $flie_name = ROOT . 'includes/lib/AppStore/Hover.json'; //配置文件名
        $Data = json_decode(file_get_contents($flie_name), TRUE);
        if (count($Data) == 0) return false;
        $DataArr = [];
        foreach ($Data as $value) {
            $dir = ROOT . '/includes/lib/soft/conf/' . $value;
            if (!is_dir($dir)) continue;
            if ($type == 1) {
                $App = self::AppConf($value);
                $DataArr[] = [
                    'id' => $value,
                    'name' => $App['name'],
                    'versions' => $App['versions'],
                    'state' => $App['state'],
                    'image' => ImageUrl($App['image'])
                ];
            } else $DataArr[] = $value;
        }
        if (count($DataArr) == 0) return false;

        return $DataArr;
    }

    /**
     * @param $Arr
     * 更新悬停列表数据！
     */
    public static function HoverSet($Arr)
    {
        $myfile = fopen(ROOT . 'includes/lib/AppStore/Hover.json', "w") or dies(-1, '悬停配置文件写入失败！');
        $r = fwrite($myfile, json_encode($Arr, JSON_UNESCAPED_UNICODE));
        fclose($myfile);
        if ($r) {
            return true;
        } else return false;
    }

    /**
     * @param array $Rule
     * 存储规则！
     */
    public static function RuleSet($Rule = [])
    {
        $RuleFs = fopen(ROOT . 'includes/lib/rule/rule.php', 'w') or dies(-1, '无法读取规则配置文件，请初始化规则！');
        $_SESSION['Rule'] = null;
        $i = '';
        $Test = "";
        foreach ($Rule as $key => $value) {
            if ($value['type'] == -1) {
                //api
                $Test .= "
    '" . $key . "' => [
        'name' => '" . $value['name'] . "',
        'type' => -1,
        'url' => '" . $value['url'] . "',
        'way' => " . $value['way'] . ",
        'placeholder' => '" . $value['placeholder'] . "',
    ],";
            } else {
                //收货地址
                $Test .= "
    '" . $key . "' => [
        'name' => '" . $value['name'] . "',
        'type' => 1,
        'way' => 1,
        'placeholder' => '" . $value['placeholder'] . "',
    ],";
            }
        }
        $Php = "<?php
session_start();
$" . $i . "_SESSION['Rule'] = [" . $Test . "
];

?>
";
        if (fwrite($RuleFs, $Php)) {
            fclose($RuleFs);
            return [
                'code' => 1,
                'msg' => '配置文件写入成功',
            ];
        } else return [
            'code' => -1,
            'msg' => '配置文件写入失败',
        ];
    }

    /**
     * @param $Data 传值数据
     * 获取应用列表！
     * install_state 是否安装 1安装，-1未安装
     * run_state 是否启动 1启动，-1未启动
     * versions_state 是否需要更新 1需要，-1不需要
     */
    public static function ApplyList($Data, $type = 1)
    {
        global $accredit;
        if (isset($_SESSION["applists_" . md5(json_encode($Data))]) && $type == 1) {
            $List = json_decode($_SESSION["applists_" . md5(json_encode($Data))], TRUE);
        } else {
            $List = Curl::curl(false, $Data, true, '/wxapi/view/ajax/application.ajax', 2);
            if ($List['code'] < 0) dier($List);
            $_SESSION["applists_" . md5(json_encode($Data))] = json_encode($List, JSON_UNESCAPED_UNICODE);
        }
        $Data = [];

        $Hover = self::HoverList(2);

        foreach ($List['data'] as $value) {
            $dir = ROOT . '/includes/lib/soft/conf/' . $value['identification'];
            if (is_dir($dir)) {
                $value['install_state'] = 1;
            } else {
                $value['install_state'] = -1;
            }

            if (in_array($value['identification'], $Hover)) {
                $value['Hover'] = 1;
            } else $value['Hover'] = -1;

            if (!file_exists($dir . '/' . $accredit['token'] . '_conf.json') || $value['state'] == -1 || $value['state'] == 2) {
                /**
                 * 未安装或未购买到期状态
                 */
                $value['run_state'] = -1;
                $value['versions_state'] = -1;
                $value['update_instructions'] = -1;
            } else {
                /**
                 * 已安装，且未到期状态！
                 */
                $vis = json_decode(file_get_contents($dir . '/' . $accredit['token'] . '_conf.json'), TRUE);
                $value['run_state'] = -1;
                if (empty($vis['versions']) || empty($vis['state'])) {
                    $value['run_state'] = -1;
                    $value['versions_state'] = -1;
                    $value['update_instructions'] = -1;
                } else {
                    if ((float)$value['versions'] > (float)$vis['versions']) {
                        $value['versions_state'] = 1;
                    } else {
                        $value['versions_state'] = -1;
                        $value['update_instructions'] = -1;
                    }
                    $value['run_state'] = (int)$vis['state'];
                }
            }
            $value['load'] = false;
            $Data[] = $value;
        }

        $List['data'] = $Data;
        dier($List);
    }

    /**
     * @param $id
     * @return bool|mixed
     * 查询应用详细信息，无下载地址
     */
    public static function AppDataS($id)
    {
        $AppData = Curl::curl(false, ['act' => 'AppDataId', 'id' => $id], true, '/wxapi/view/ajax/application.ajax', 2);
        return $AppData;
    }

    /**
     * @param $ID
     * 获取指定ID的应用数据,用于安装！
     */
    public static function appdata($ID)
    {
        $AppData = Curl::curl(false, ['act' => 'AppData', 'id' => $ID], true, '/wxapi/view/ajax/application.ajax', 2);
        return $AppData;
    }

    /**
     * @param $ID AppList
     * @param int $Type 1 安装，2升级
     * 安装程序
     */
    public static function install($ID, $Type = 1)
    {
        global $accredit;
        $Data = self::appdata($ID);
        if ($Data['code'] < 0) dier($Data);
        $ZipFile = $Data['data']['identification'] . '.zip';
        copy($Data['data'][($Type == 1 ? 'download' : 'download_update')], $ZipFile) or dies(-1, '无法下载文件,请重新尝试！');
        if ($Type == 2) {
            /**
             * 更新前先卸载除配置外的旧文件，防止文件权限不足无法写入覆盖！
             */
            unlink(ROOT . 'includes/lib/soft/conf/' . $Data['data']['identification'] . '/help.html');
            \file_operations::deldir(ROOT . 'includes/lib/soft/controller/' . $Data['data']['identification'] . '/');
            \file_operations::deldir(ROOT . 'includes/lib/soft/view/' . $Data['data']['identification'] . '/');
        }

        if (\file_operations::zipExtract($ZipFile, ROOT . $Data['data']['path'])) {

            if (file_exists($ZipFile)) {
                unlink($ZipFile);
            }

            $flie = ROOT . 'includes/lib/soft/conf/' . $Data['data']['identification'] . '/';
            if (!is_dir($flie)) {
                mkdir($flie, 0777, true);
            }

            $flie_name = ROOT . 'includes/lib/soft/conf/' . $Data['data']['identification'] . '/' . $accredit['token'] . '_conf.json'; //配置文件名

            if ($Type == 2) {
                $DataS = json_decode(file_get_contents($flie_name), TRUE);
            }

            $myfile = fopen($flie_name, "w") or dies(-1, '程序配置文件写入失败！');


            if ($Data['data']['Global'] == 1) {
                $AroConf = self::ConfGlobal();
                self::ConfGlobal(2, array_merge($AroConf, [$Data['data']['identification']]));
            }

            if ($Type == 1) {
                /**
                 * 安装
                 */
                $DataS = [
                    'name' => $Data['data']['name'],
                    'versions' => $Data['data']['versions'],
                    'state' => 1,
                    'identification' => $Data['data']['identification'],
                    'visit' => $Data['data']['visit'],
                    'image' => $Data['data']['image'],
                    'id' => $Data['data']['id'],
                ];
            } else {
                /**
                 * 升级
                 */
                if ($DataS['identification'] == null) dies(-1, '升级失败，无法读取配置文件,请重新尝试！');
                $DataS['name'] = $Data['data']['name'];
                $DataS['versions'] = $Data['data']['versions'];
                $DataS['visit'] = $Data['data']['visit'];
                $DataS['image'] = $Data['data']['image'];
                $DataS['id'] = $Data['data']['id'];
            }

            if ($Type == 1) {
                /**
                 * 验证是否为支付接口应用！
                 */
                $flie = ROOT . 'includes/lib/soft/conf/' . $Data['data']['identification'] . '/payconf.json';
                if (file_exists($flie)) {
                    $vis = json_decode(file_get_contents($flie), TRUE);
                    $arr = [];

                    for ($s = 0; $s < 3; $s++) {
                        for ($i = 0; $i < count(explode(',', $vis['input'])); $i++) {
                            $arr[$s][] = '';
                        }
                    }

                    $DataS = array_merge($DataS, [
                        'Data' => $arr,
                    ]);
                    self::pay_set($Data['data'], 1);
                }
            }

            /**
             * 验证是否需要将此应用注册到对应钩子
             */
            $flie = ROOT . 'includes/lib/soft/conf/' . $Data['data']['identification'] . '/Hook.json';
            if (file_exists($flie)) {
                $HookArr = json_decode(file_get_contents($flie), TRUE);
                foreach ($HookArr as $value) {
                    Hook::add($value, $Data['data']['identification']);
                }
            }

            fwrite($myfile, json_encode($DataS, JSON_UNESCAPED_UNICODE));
            fclose($myfile);

            dies(1, $Data['data']['name'] . ($Type == 1 ? '安装成功！' : '更新成功！'));
        } else {
            if (file_exists($ZipFile)) {
                unlink($ZipFile);
            }
            dies(-1, '无法解压文件,ZipArchive类无法使用！');
        }
    }

    /**
     * @param array $Data 数据
     * @param int $Type 类型 1=读取，2=写入
     * 全局文件调用管理
     */
    public static function ConfGlobal($Type = 1, array $Data = [])
    {
        $flie_name = ROOT . 'includes/lib/AppStore/confs.json';
        $aRRS = json_decode(file_get_contents($flie_name), TRUE);
        if ($Type == 1) {
            return $aRRS;
        } else {
            $myfile = fopen($flie_name, "w") or dies(-1, '程序配置文件写入失败！');
            $r = fwrite($myfile, json_encode($Data, JSON_UNESCAPED_UNICODE));
            fclose($myfile);
            if ($r) {
                return true;
            } else return false;
        }
    }

    /**
     * @param $identification
     * 卸载指定应用！
     */
    public static function unload($identification)
    {
        $msg = '卸载状态：<br>';
        $Arra = ['conf', 'controller', 'view'];

        /**
         * 验证是否为支付接口应用，如果是则删除！
         */
        $flie = ROOT . 'includes/lib/soft/conf/' . $identification . '/payconf.json';
        if (file_exists($flie)) {
            self::pay_set(['identification' => $identification], 2);
            $msg .= '对应支付配置清除成功<br>';
        }

        /**
         * 删除对应钩子！
         */
        $flie = ROOT . 'includes/lib/soft/conf/' . $identification . '/Hook.json';
        if (file_exists($flie)) {
            $HookArr = json_decode(file_get_contents($flie), TRUE);
            foreach ($HookArr as $value) {
                Hook::delete($value, $identification);
            }
            $msg .= '钩子配置(' . count($HookArr) . ')个,清除成功<br>';
        }

        foreach ($Arra as $value) {
            $flie_name = ROOT . 'includes/lib/soft/' . $value . '/' . $identification . '/'; //配置文件名
            $a = \file_operations::deldir($flie_name);
            switch ($value) {
                case 'conf':
                    if ($a) {
                        $msg .= '配置文件删除成功<br>';
                    } else $msg .= '配置文件删除失败<br>';
                    break;
                case 'controller':
                    if ($a) {
                        $msg .= '控制器文件删除成功<br>';
                    } else $msg .= '控制器文件删除失败<br>';
                    break;
                case 'view':
                    if ($a) {
                        $msg .= '视图文件删除成功<br>';
                    } else $msg .= '视图文件删除失败<br>';
                    break;
            }
        }

        $AroConf = self::ConfGlobal();
        foreach ($AroConf as $k => $v) {
            if ($v == $identification) unset($AroConf[$k]);
        }

        self::ConfGlobal(2, $AroConf);

        $flie_name = ROOT . 'template/' . $identification . '/';
        \file_operations::deldir($flie_name);

        dies(1, $msg);
    }

    /**
     * @param int $state 状态码
     * @param string $msg 说明
     * 异常反馈,短文字
     */
    public static function error($state = 404, $msg = '页面不存在')
    {
        @header('Content-Type: text/html; charset=UTF-8');
        @header('HTTP/1.1 ' . $state . ' ' . $msg);
        $Data = file_get_contents(ROOT . '/includes/lib/AppStore/error.TP');
        $Data = str_replace('[STATE]', $state, $Data);
        die(str_replace('[MSG]', $msg, $Data));
    }

    /**
     * @param $identification 软件标识
     * @param $path 访问目录！
     * @param $t AppList
     *
     */
    public static function view($identification, $path, $t)
    {
        global $conf, $cdnserver, $cdnpublic, $dbconfig, $accredit;
        $dir = ROOT . '/includes/lib/soft/conf/' . $identification;
        $vis = json_decode(file_get_contents($dir . '/' . $accredit['token'] . '_conf.json'), TRUE);
        if (empty($vis['versions']) || empty($vis['state'])) self::error(404, '应用未安装');
        if ($vis['state'] <> 1) self::error(401, '应用未启用');
        $Data = self::appdata($t);
        if ($Data['code'] < 0) show_msg('警告', (empty($Data['msg']) ? '无法获取应用数据,请检查是否可以和服务端通讯！' : $Data['msg']), false, false, false);
        $DB = SQL::DB();
        $file = ROOT . 'includes/lib/soft/view/' . $identification . '/' . $path . '.TP';
        if (!file_exists($file)) self::error(404, '无设置面板');
        include_once $file;
        die();
    }

    /**
     * @param $flie 文件路径
     * @param $data 应用数据
     * @param int $type 1=新增，2=删除
     * 支付JSON配置文件调整
     */
    public static function pay_set($data, $type = 1)
    {
        $Fvis = self::PayConf($data['identification']);
        if ($type == 1) {
            $vis = json_decode(file_get_contents(ROOT . 'includes/lib/soft/conf/' . $data['identification'] . '/payconf.json'), TRUE);

            $Vie = json_decode(file_get_contents(ROOT . 'includes/lib/AppStore/pay.json'), TRUE);

            if (count($Vie) >= 1) {
                foreach ($Vie as $vi) {
                    if ($vi['identification'] == $data['identification']) return true;
                }
            }

            $Fvis = array_merge($Fvis, [[
                'name' => $data['name'],
                'state' => $vis['state'],
                'identification' => $data['identification'],
                'input' => $vis['input'],
            ]]);
        } else {
            $Ds = [];
            foreach ($Fvis as $v) {
                if ($v['identification'] != $data['identification']) {
                    $Ds[] = $v;
                }
            }
            $Fvis = $Ds;
        }

        $myfile = fopen(ROOT . 'includes/lib/AppStore/pay.json', "w") or dies(-1, '程序配置文件写入失败！');
        $r = fwrite($myfile, json_encode($Fvis, JSON_UNESCAPED_UNICODE));
        fclose($myfile);
        if ($r) {
            return true;
        } else return false;
    }

    /**
     * @param $Data 配置数据
     * @param $identification 标识
     * @param $type 类型
     */
    public static function SavePayData($Data, $identification, $type)
    {
        global $accredit;
        $i = 1;
        foreach ($Data as $v) {
            if ($v == '') dies(-1, '请将第' . $i . '个输入框填写完整！');
            ++$i;
        }
        $flie_name = ROOT . 'includes/lib/soft/conf/' . $identification . '/' . $accredit['token'] . '_conf.json'; //配置文件内容读取
        $vis = json_decode(file_get_contents($flie_name), TRUE);
        if (empty($vis['versions']) || empty($vis['state'])) dies(-1, '当前应用尚未安装，配置文件不存在！');
        $vis['Data'][$type] = $Data;
        $myfile = fopen($flie_name, "w") or dies(-1, '程序配置文件读取失败！');
        fwrite($myfile, json_encode($vis, JSON_UNESCAPED_UNICODE));
        fclose($myfile);
        dies(1, $vis['name'] . '的' . ($type == 0 ? 'QQ支付配置' : ($type == 1 ? '微信支付配置' : '支付宝支付配置')) . '保存成功!');
    }

    /**
     * @param $identification 标识
     * @param int $type 类型
     * 应用状态修改！
     */
    public static function state_set($identification, $type = 1)
    {
        global $accredit;
        $flie_name = ROOT . 'includes/lib/soft/conf/' . $identification . '/' . $accredit['token'] . '_conf.json'; //配置文件名
        $vis = json_decode(file_get_contents($flie_name), TRUE);
        if (empty($vis['versions']) || empty($vis['state'])) dies(-1, '当前应用尚未安装，配置文件不存在！');
        $myfile = fopen($flie_name, "w") or dies(-1, '程序配置文件读取失败！');
        $vis['state'] = ($type == 1 ? 1 : 2);
        fwrite($myfile, json_encode($vis, JSON_UNESCAPED_UNICODE));
        fclose($myfile);
        dies(1, $vis['name'] . '已' . ($type == 1 ? '启用' : '停用') . '!');
    }

    /**
     * @param $id 应用ID
     * 延长到期时间
     */
    public static function prolong($id)
    {
        $AppData = Curl::curl(false, ['act' => 'AppProlong', 'id' => $id], true, '/wxapi/view/ajax/application.ajax', 2);
        dier($AppData);
    }

    /**
     * @param $ID
     * 购买应用！
     */
    public static function pay($ID)
    {
        $AppData = Curl::curl(false, ['act' => 'AppPay', 'id' => $ID], true, '/wxapi/view/ajax/application.ajax', 2);
        dier($AppData);
    }

    /**
     * 获取用户等级
     */
    public static function users()
    {
        $AppData = Curl::curl(false, ['act' => 'AppUsers'], true, '/wxapi/view/ajax/application.ajax', 2);
        dier($AppData);
    }

    /**
     * 站长后台登陆验证，插件版
     */
    public static function AdminVerify()
    {
        $DB = SQL::DB();
        if (empty($_COOKIE['ADMIN_TOKEN'])) return false;
        if (strlen($_COOKIE['ADMIN_TOKEN']) <> 32) {
            setcookie("ADMIN_TOKEN", null, time() - 3600 * 12 * 15, '/');
            return false;
        } else {
            $A = $DB->get('login', ['token'], ['token' => $_COOKIE['ADMIN_TOKEN'], 'state' => 1, 'LIMIT' => 1]);
            if (!$A) {
                setcookie("ADMIN_TOKEN", null, time() - 3600 * 12 * 15, '/');
                return false;
            } else return true;
        }
    }

    /**
     * 用户后台登陆验证，插件版
     */
    public static function UserVerify()
    {
        $DB = \Medoo\DB\SQL::DB();
        if (empty($_COOKIE['THEKEY'])) {
            return false;
        } else {
            if (strlen($_COOKIE['THEKEY']) == 32) {
                $user_row = $DB->get('user', ['id', 'user_idu', 'state'], ['user_idu' => $_COOKIE['THEKEY'], 'state' => 1, 'LIMIT' => 1]);
            } else {
                $user_row = $DB->get('user', ['id', 'wx_idu', 'state'], ['wx_idu' => $_COOKIE['THEKEY'], 'state' => 1, 'LIMIT' => 1]);
            }
            if (!$user_row) {
                setcookie("THEKEY", null, time() - 3600 * 12 * 15, '/');
                return false;
            } else return true;
        }
    }

    /**
     * @param $identification 配置文件软件标识
     * 查询配置文件
     */
    public static function AppConf($identification)
    {
        global $accredit;
        $flie_name = ROOT . 'includes/lib/soft/conf/' . $identification . '/' . $accredit['token'] . '_conf.json'; //配置文件名
        return json_decode(file_get_contents($flie_name), TRUE);
    }

    /**
     * 读取支付配置列表
     */
    public static function PayConf()
    {
        $flie_name = ROOT . 'includes/lib/AppStore/pay.json'; //配置文件名
        return json_decode(file_get_contents($flie_name), TRUE);
    }

    /**
     * @param null $identification 应用标识
     * 帮助文档
     */
    public static function AppHelp($identification = null)
    {
        $file = ROOT . 'includes/lib/soft/conf/' . $identification . '/help.html';
        if (!file_exists($file)) self::error(404, '帮助文档不存在');
        @header('Content-Type: text/html; charset=UTF-8');
        include_once $file;
    }

    /**
     * @param $identification
     * @param $Data
     * Api钩子
     */
    public static function Api($identification = null, $Data = [], $Types = true)
    {
        @header('Content-Type: application/json; charset=UTF-8');
        if (empty($identification)) {
            if ($Types == true) dies(-1, '应用标识为空,请联系开发者处理！');
            return false;
        }

        $Flie = ROOT . 'includes/lib/soft/controller/' . $identification . '/index.php';
        if (!file_exists($Flie)) {
            if ($Types == true) dies(-1, '此应用控制器不存在！');
            return false;
        }

        if (self::AppConf($identification)['state'] <> 1) {
            if ($Types == true) dies(-1, '应用' . self::AppConf($identification)['name'] . '处于关闭状态！');
            return false;
        }

        /**
         * 验证权限
         */

        $ArrConf = explode(',', self::AppConf($identification)['visit']);
        if (in_array('Admin', $ArrConf)) {
            if (self::AdminVerify() == false) return false;
        } else if (in_array('User', $ArrConf)) {
            if (self::UserVerify() == false) return false;
        }
        include_once $Flie;
        $nAM = '\\lib\\' . $identification;
        $C = new $nAM();

        if ($Data['HookName'] == 'OrderPriceSet') {
            $Dat = $C->origin($Data);
            if (!empty($Dat['Gid']) && !empty($Dat['Price']) && !empty($Dat['InputData']) && !empty($Dat['Num'])) return $Dat;
        } else $C->origin($Data);
    }

    /**
     * @param array $Data
     * 全局拦截器
     */
    public static function Globals(array $Data)
    {
        $flie_name = ROOT . 'includes/lib/AppStore/confs.json';
        $aRRS = json_decode(file_get_contents($flie_name), TRUE);
        if (count($aRRS) == 0) return;
        foreach ($aRRS as $v) {
            self::Api($v, $Data, false);
        }
    }
}